2012/11/05

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

前回は JSMN というのを試したけど、今度も matsuu さんのブクマから。。。
parson

Lightweight json parser and reader written in C.

http://kgabis.github.com/parson/
特徴は
  • 軽い (2ファイルだけ)
  • 単純なAPI
  • ドット記法による json 値のアドレッシング (C言語の構造体やOO言語のオブジェクトに似た感じ。例: "objectA.objectB.value")
  • C89 コンパティブル
  • テストスーツ
前回の JSMN とは違い、メモリを動的に確保するタイプ。DOM の様にルートノードから探索を始め、最終的にルートノードを指定してメモリを開放する。
今回もtwitterのタイムラインをパースしよう。 #include <assert.h>
#include <string.h>
#include <memory.h>
#include <curl/curl.h>
#include "parson.h"

typedef struct {
  char* data;   // response data from server
  size_t size;  // response size of data
} MEMFILE;

MEMFILE*
memfopen() {
  MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE));
  if (mf) {
    mf->data = NULL;
    mf->size = 0;
  }
  return mf;
}

void
memfclose(MEMFILE* mf) {
  if (mf->data) free(mf->data);
  free(mf);
}

size_t
memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) {
  MEMFILE* mf = (MEMFILE*) stream;
  int block = size * nmemb;
  if (!mf) return block; // through
  if (!mf->data)
    mf->data = (char*) malloc(block);
  else
    mf->data = (char*) realloc(mf->data, mf->size + block);
  if (mf->data) {
    memcpy(mf->data + mf->size, ptr, block);
    mf->size += block;
  }
  return block;
}

char*
memfstrdup(MEMFILE* mf) {
  char* buf;
  if (mf->size == 0return NULL;
  buf = (char*) malloc(mf->size + 1);
  memcpy(buf, mf->data, mf->size);
  buf[mf->size] = 0;
  return buf;
}

int
main() {
  CURL* curl;
  MEMFILE* mf = NULL;
  char* js = NULL;
  int i;

  mf = memfopen();

  curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_URL, "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=otsune");
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
  curl_easy_perform(curl);
  curl_easy_cleanup(curl);

  js = memfstrdup(mf);
  memfclose(mf);

  JSON_Value *root_value = json_parse_string(js);
  JSON_Array *tweets = json_value_get_array(root_value);
  for (i = 0; i < json_array_get_count(tweets); i++) {
    JSON_Object *tweet = json_array_get_object(tweets, i);
    printf("%s%s\n",
      json_object_dotget_string(tweet, "user.screen_name"),
      json_object_dotget_string(tweet, "text"));
  }

  json_value_free(root_value);
  free(js);
}
なにこれ!めちゃ簡単。しかもソースを見たところユニコードに対応してる。そしてドット演算子、良いすね。JSON XPath の様ですね。ただ残念ながら JSON XPath の様に .. でスキップする機能は無かったですが。

しかしながらこれC言語の JSON パーサの中では、私が知る限り一番扱いやすいと思いますね。(C++は別です)
MIT ライセンスなのでプロジェクトでも使って行きたいと思います。
Posted at by